package hell.satan.droidbdf.utils;

import android.text.TextUtils;

import java.util.Locale;

/**
 * 数字工具类
 * Numeric utils
 *
 * @author Cerberus
 */
@SuppressWarnings("unused")
public class NumericUtils {
    protected static final String NUMBER_SIGN_EN = "negative";

    protected static final String[] NUMBER_BASE_EN = {
            "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
            "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
            "nineteen", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
    };

    protected static final String[] NUMBER_UNIT_EN = {
            "hundred", "thousand", "million", "billion", "trillion", "quintillion"
    };

    protected static final String[] NUMBER_OTHER_EN = {" ", ",", "and"};

    protected static final String NUMBER_SIGN_ZH = "负";

    protected static final String[] NUMBER_BASE_ZH_LOWER = {
            "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九"
    };

    protected static final String NUMBER_SIGN_ZH_CN_LOWER = NUMBER_SIGN_ZH;

    protected static final String[] NUMBER_BASE_ZH_CN_LOWER = NUMBER_BASE_ZH_LOWER;

    protected static final String[] NUMBER_UNIT_ZH_CN_LOWER = {"十", "百", "千", "万", "亿", "兆"};

    protected static final String NUMBER_SIGN_ZH_TW_LOWER = NUMBER_SIGN_ZH;

    protected static final String[] NUMBER_BASE_ZH_TW_LOWER = NUMBER_BASE_ZH_LOWER;

    protected static final String[] NUMBER_UNIT_ZH_TW_LOWER = {"十", "百", "千", "萬", "億", "兆"};

    protected static final String[] NUMBER_BASE_ZH_UPPER = {
            "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"
    };

    protected static final String NUMBER_SIGN_ZH_CN_UPPER = NUMBER_SIGN_ZH;

    protected static final String[] NUMBER_BASE_ZH_CN_UPPER = NUMBER_BASE_ZH_UPPER;

    protected static final String[] NUMBER_UNIT_ZH_CN_UPPER = {"拾", "佰", "仟", "万", "亿", "兆"};

    protected static final String NUMBER_SIGN_ZH_TW_UPPER = NUMBER_SIGN_ZH;

    protected static final String[] NUMBER_BASE_ZH_TW_UPPER = NUMBER_BASE_ZH_UPPER;

    protected static final String[] NUMBER_UNIT_ZH_TW_UPPER = {"拾", "佰", "仟", "萬", "億", "兆"};

    /**
     * 将阿拉伯数字转换成本地语言
     * Transforming Arabic numerals into a native language
     *
     * @param locale 转换的语言
     *               Transforming native language
     * @param number 待转换数字
     *               The number to be transformed
     * @param upper  是否转换成大写
     *               Whether to use upper letters. In some native language, between lower case number
     *               and upper case number is different.
     *               For example, in Chinese, 1 for lower case is 一, for upper case is 壹
     * @return 本地语言的数字。 Number in native language
     */
    @SuppressWarnings("deprecation")
    public static String number2Word(Locale locale, long number, boolean upper) {
        String language = locale.getLanguage();
        switch (language) {
            case "zh": {
                return TextUtils.equals(locale.getCountry(), "CN")
                        ? number2zh_CN(number, upper) : number2zh_TW(number, upper);
            }
            case "en":
            default: {
                return number2en(number);
            }
        }
    }

    /**
     * 将阿拉伯数字转换成本地语言
     * Transforming Arabic numerals into a native language
     *
     * @param locale 转换的语言
     *               Transforming native language
     * @param number 待转换数字
     *               The number to be transformed
     * @return 本地语言的数字。 Number in native language
     */
    public static String number2Word(Locale locale, long number) {
        return number2Word(locale, number, false);
    }

    /**
     * 将阿拉伯数字转换成本地语言
     * Transforming Arabic numerals into a native language
     *
     * @param number 待转换数字
     *               The number to be transformed
     * @return 本地语言的数字。 Number in native language
     */
    public static String number2Word(long number) {
        return number2Word(Locale.getDefault(), number);
    }

    /**
     * 将阿拉伯数字转换成英语
     * Transforming Arabic numerals into English
     *
     * @param number 待转换数字
     *               The number to be transformed
     * @return 英语数字。 Number in English
     * @deprecated use number2Word(Locale.EN, number)
     */
    @Deprecated
    public static String number2en(long number) {
        if (number == 0) return NUMBER_BASE_EN[0];

        final int SIZE_GROUP = 3;
        String string = String.valueOf(Math.abs(number));
        int len = string.length();
        int group = len / SIZE_GROUP + ((len % SIZE_GROUP == 0) ? 0 : 1);
        if (group > NUMBER_UNIT_EN.length) {
            throw new NumberFormatException(number + " is too big");
        }

        // 逆序分组，方便组合单位。例：12345678->[678, 345, 12]
        String[] packet = new String[group];
        for (int i = 0; i < group; i++) {
            int end = len - i * SIZE_GROUP;
            packet[i] = string.substring(Math.max(0, end - SIZE_GROUP), end);
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < group; i++) {
            if (sb.length() > 0 && !(sb.charAt(0) == ',')) {
                sb.insert(0, ", ");
            }
            StringBuilder part = new StringBuilder();
            int value = Integer.valueOf(packet[i]);
            if (value >= 100) {
                part.append(NUMBER_BASE_EN[value / 100]);
                part.append(" ");
                part.append(NUMBER_UNIT_EN[0]);
                value = value % 100;
                if (value != 0) part.append(" and ");
            }
            if (value > 0 && value <= 20) {
                part.append(NUMBER_BASE_EN[value]);
            } else if (value > 0) {
                part.append(NUMBER_BASE_EN[(value - 20) / 10 + 20]);
                value = value % 10;
                if (value != 0) {
                    part.append("-");
                    part.append(NUMBER_BASE_EN[value]);
                }
            }
            if (part.length() > 0 && i > 0) {
                part.append(" ");
                part.append(NUMBER_UNIT_EN[i]);
            }
            sb.insert(0, part);
        }
        if (number < 0) {
            sb.insert(0, " ");
            sb.insert(0, NUMBER_SIGN_EN);
        }
        return sb.toString();
    }

    /**
     * 将阿拉伯数字转换成简体中文
     * Transforming Arabic numerals into Simplified Chinese
     *
     * @param number 待转换数字
     *               The number to be transformed
     * @param upper  是否转换成大写
     *               Whether to use upper letters.
     * @return 简体中文数字。 Number in Simplified Chinese
     * @see #number2zh(long, boolean, boolean)
     * @deprecated use number2Word(Locale.PRC, number)
     */
    @Deprecated
    public static String number2zh_CN(long number, boolean upper) {
        return number2zh(number, upper, true);
    }

    /**
     * 将阿拉伯数字转换成繁体中文
     * Transforming Arabic numerals into Traditional Chinese
     *
     * @param number 待转换数字
     *               The number to be transformed
     * @param upper  是否转换成大写
     *               Whether to use upper letters.
     * @return 繁体中文数字。 Number in Traditional Chinese
     * @see #number2zh(long, boolean, boolean)
     * @deprecated use number2Word(Locale.PRC, number)
     */
    @Deprecated
    public static String number2zh_TW(long number, boolean upper) {
        return number2zh(number, upper, false);
    }

    /**
     * 将阿拉伯数字转换成中文
     * Transforming Arabic numerals into Chinese
     *
     * @param number 待转换数字
     *               The number to be transformed
     * @param upper  是否转换成大写
     *               Whether to use upper letters.
     * @param sORt   中文简体或繁体，true表示生简体，false表示繁体
     *               Simplified or Traditional Chinese, true for Simplified
     * @return 中文数字。 Number in Chinese
     */
    protected static String number2zh(long number, boolean upper, boolean sORt) {
        String sign;
        String[] base;
        String[] unit;
        if (upper && sORt) {
            sign = NUMBER_SIGN_ZH_CN_UPPER;
            base = NUMBER_BASE_ZH_CN_UPPER;
            unit = NUMBER_UNIT_ZH_CN_UPPER;
        } else if (upper) {
            sign = NUMBER_SIGN_ZH_TW_UPPER;
            base = NUMBER_BASE_ZH_TW_UPPER;
            unit = NUMBER_UNIT_ZH_TW_UPPER;
        } else if (sORt) {
            sign = NUMBER_SIGN_ZH_CN_LOWER;
            base = NUMBER_BASE_ZH_CN_LOWER;
            unit = NUMBER_UNIT_ZH_CN_LOWER;
        } else {
            sign = NUMBER_SIGN_ZH_TW_LOWER;
            base = NUMBER_BASE_ZH_TW_LOWER;
            unit = NUMBER_UNIT_ZH_TW_LOWER;
        }
        if (number == 0) return base[0];

        final int SIZE_GROUP = 4;
        String string = String.valueOf(Math.abs(number));
        int len = string.length();
        int group = len / SIZE_GROUP + ((len % SIZE_GROUP == 0) ? 0 : 1);
        if (group > NUMBER_UNIT_EN.length - 2) {
            throw new NumberFormatException(number + " is too big");
        }

        String[] packet = new String[group];
        for (int i = 0; i < group; i++) {
            int start = len - (group - i) * SIZE_GROUP;
            packet[i] = string.substring(Math.max(start, 0), start + SIZE_GROUP);
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < group; i++) {
            StringBuilder part = new StringBuilder();
            int value = Integer.valueOf(packet[i]);
            if (value >= 1000) {
                part.append(base[value / 1000]);
                part.append(unit[2]);
                value = value % 1000;
                if (value != 0 && value < 100) part.append(base[0]);
            } else if (sb.length() > 0 && value != 0) {
                part.append(base[0]);
            }
            if (value >= 100) {
                part.append(base[value / 100]);
                part.append(unit[1]);
                value = value % 100;
                if (value != 0 && value < 10) part.append(base[0]);
            }
            if (value >= 10) {
                if (part.length() > 0 || value / 10 != 1) part.append(base[value / 10]);
                part.append(unit[0]);
                value = value % 10;
            }
            if (value != 0) part.append(base[value]);
            if (part.length() > 0) {
                if (i < group - 1) part.append(unit[group - i + 1]);
                sb.append(part);
            }
        }
        if (number < 0) sb.insert(0, sign);
        return sb.toString();
    }
}
